# -*- coding: utf-8 -*-
# @name             : 压力测试
# @author           : OneYoung
# @create           : 2024/07/18
# @version          : v1.0
# @desc             :

import time
import threading
from utils.log_record import logger


class StressTest:
    """接口压力测试"""

    def __init__(self):
        self.response = None
        self.num = 0  # 定义执行次数
        self.error_num = 0  # 定义错误次数

    # 接口断言
    def __interface_assert(self):
        status_code = self.response.status_code
        self.num += 1
        if status_code != 200:
            self.error_num += 1
            return

    # 添加thread_num个任务到线程中，执行并发(非绝对并发)
    def __thread_list(self, thread_num, func_list):
        Threads = []
        for i in range(thread_num):
            for func in func_list:
                self.response = func
                t = threading.Thread(target=self.__interface_assert, name='T' + str(i))
                t.daemon = True  # 设置成守护线程
                Threads.append(t)

        for t in Threads:
            t.start()
        for t in Threads:
            t.join()

    # 执行压力测试
    def run(self, func_list: str | list, thread_num: int, cycle_index: int, loop_time: int | float):
        """
        :param func_list: 压测接口名称func_name|[func_name]
        :param thread_num: 并发数量
        :param cycle_index: 循环次数
        :param loop_time: 循环间隔时间(秒)
        """
        func_list = func_list
        if not isinstance(func_list, list):
            if callable(func_list):
                func_list = [func_list]
            else:
                raise TypeError("不是有效的函数")
        fun_num = len(func_list)
        start_time = time.time()  # 执行开始时间

        # 循环执行cycle_index次
        for cycle in range(cycle_index):
            self.__thread_list(thread_num, func_list)
            time.sleep(loop_time)

        end_time = time.time()  # 执行结束时间
        total_time = end_time - start_time  # 总耗时
        task_num = thread_num * fun_num * cycle_index  # 任务数

        # 打印结果,输出日志
        task_num_info = f"({thread_num} * {fun_num}) * {cycle_index} = {task_num}"
        logger.info("=================== STRESS RESULT ===================")
        logger.info("TASKS NUM:" + task_num_info)
        logger.info("TOTAL TIME(S):" + str(total_time))
        logger.info("ONE TIME REQUEST TIME(S):" + str(total_time / task_num))
        logger.info("REQUESTS PER SECOND:" + str(1 / (total_time / task_num)))
        logger.info("ERROR NUM:" + str(self.error_num) + "\n")
